# coding=utf-8
"""
进程同步之：Condition
一个condition变量总是与某些类型的锁相联系，当几个condition变量必须共享同一个锁的时候，是很有用的。锁是conditon对象的一部分：没有必要分别跟踪。
condition变量服从上下文管理协议：with语句块封闭之前可以获取与锁的联系。 acquire() 和release() 会调用与锁相关联的相应方法。
wait()方法会释放锁，当另外一个进程使用notify() or notify_all()唤醒它之前会一直阻塞。一旦被唤醒，wait()会重新获得锁并返回，Condition类实现了一个conditon变量。这个condition变量允许一个或多个进程等待，直到他们被另一个进程通知。如果lock参数，被给定一个非空的值，那么他必须是一个lock或者Rlock对象，它用来做底层锁。否则，会创建一个新的Rlock对象，用来做底层锁。
wait(timeout=None) ：等待通知，或者等到设定的超时时间。当调用wait()方法时，如果调用它的进程没有得到锁，那么会抛出一个RuntimeError异常。 wait()释放锁以后，在被调用相同条件的另一个进程用notify() or notify_all() 叫醒之前会一直阻塞。如果有等待的进程，notify()方法会唤醒一个在等待conditon变量的进程。notify_all() 则会唤醒所有在等待conditon变量的进程。
注意：
notify()和notify_all()不会释放锁，也就是说，进程被唤醒后不会立刻返回他们的wait() 调用。除非进程调用notify()和notify_all()之后放弃了锁的所有权。在典型的设计风格里，利用condition变量加锁去允许访问一些共享状态，进程在获取到它想得到的状态前，会反复调用wait()。修改状态的进程在他们状态改变时调用 notify() or notify_all()，用这种方式，进程会尽可能的获取到想要的一个等待者状态。
"""
import multiprocessing as mp
import threading
import time


def consumer(cond):
    with cond:
        print("consumer before wait")
        cond.wait()  # 等待消费
        print("consumer after wait")


def producer(cond):
    with cond:
        print("producer before notifyAll")
        cond.notify_all()  # 通知消费者可以消费了
        # cond.notify() # 通知1个人，没有参数
        print("producer after notifyAll")


if __name__ == '__main__':
    condition = mp.Condition()

    p1 = mp.Process(name="p1", target=consumer, args=(condition,))
    p2 = mp.Process(name="p2", target=consumer, args=(condition,))
    p3 = mp.Process(name="p3", target=producer, args=(condition,))

    p1.start()
    time.sleep(2)
    p2.start()
    time.sleep(2)
    p3.start()
